using Gee;
using Vwf.Tools;

namespace Vwf.Vwt {
	
	public errordomain EDParser {
		UnexpectedEOF,
		ParserClassNotExists,
		UnknownBlock,
		Expected,
		Unexpected
	}

	public abstract class Parser : Object {
		public StrParser strParser;
		public Block content;
		public delegate Parser DParserCreator(); // Object? t
		public class ParserCreator {
			public DParserCreator fnCreator;
			public ParserCreator(DParserCreator fn) {
				fnCreator = fn;
			}
		}
		public HashMap<string, ParserCreator> parseCreators = new HashMap<string, ParserCreator>();
		public string[] blockTypes;
		
		public void addParserCreator(DParserCreator creator) {
			// var creator1 = creator;
			Parser parser = creator();
			// parser;
			logMsg("Trida [" + parser.get_type().name() + "]");
			foreach(string blockType in parser.blockTypes) {
				logMsg("Registruji parser pro [" + blockType + "]");
				parseCreators[blockType] = new ParserCreator(creator);
			};
		}
		
		public Parser getNextParser() throws EDParser, EDStrParser {
			// strParser.rmove(2);
			string cStart = strParser.storeCursor();
			if (strParser.findAnyNext(new string[] { " ", "\n", "\r", "\t" } )) {
				var parser = getParser(strParser.substring(cStart));
				strParser.toEndChunk();
				return parser;
			} else {
				throw new EDParser.UnexpectedEOF("");
			};
		}
		
		public Parser getParser(string name) throws EDParser, EDStrParser {
			logMsg("Dalsi parser je " + name);
			if (name in parseCreators) {
				var parser = parseCreators[name].fnCreator();
				parser.strParser = strParser;
				parser.parseCreators = parseCreators;
				parser.setBlockType(name);
				
				return parser;
			} else {
				throw new EDParser.ParserClassNotExists(name);
			};
		}
		
		public abstract void parse() throws EDParser, EDStrParser;
		
		public virtual string[] getBlockTypes() {
			return blockTypes;
		}
		
		public virtual void setBlockType(string blockType) { }
		
		public static Parser getStartParser(string str) {
			var parser = new ParserMixed();
			parser.strParser = new StrParser(str);
			parser.addParserCreator(() => new ParserMixed());
			parser.addParserCreator(() => new ParserVala());
			parser.addParserCreator(() => new ParserControl());
			
			return parser;
		}
		
		protected int passWhitespace() {
			return strParser.findNextNonChar(" \n\r\t");
		}
	}
}
